package com.inpion.biz.broker.service.util;

import java.lang.reflect.Method;
import java.sql.PreparedStatement;

import kr.co.redcircle.broker.Broker;
import kr.co.redcircle.broker.information.HostInfo;
import kr.co.redcircle.broker.information.NodeInformation;
import kr.co.redcircle.broker.io.BrokerResult;
import kr.co.redcircle.broker.registry.Registry;
import kr.co.redcircle.broker.registry.SystemAuthenticationFailureException;
import kr.co.redcircle.broker.security.KeyCollection;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;

import com.inpion.biz.broker.service.data.DataStore;

public class DataStoreUtility {

	public static void setupKeyStore(Document document) throws JDOMException, SystemAuthenticationFailureException {
		Element trustStoreElement = (Element) XPath.selectSingleNode(document, "//trustStore");
		
		if (trustStoreElement == null){
			throw new SystemAuthenticationFailureException();
			
		}else{
			
			String trustStorePath = trustStoreElement.getChild("path").getValue();
			String trustStorePass = trustStoreElement.getChild("pass").getValue();
			Element certFileElement = trustStoreElement.getChild("cert");
			String certPath = certFileElement.getChild("path").getValue();
			String certPass = certFileElement.getChild("pass").getValue();
			
			KeyCollection kCollection = Registry.getKeyCollection();
			kCollection.addTrustStore(trustStorePath, trustStorePass);
			kCollection.setupKeyStore(certPath, certPass);
			kCollection.init(certPass);
			
		}	
	}
	
	public static void setupNameNodeInformation(Element networkElement) {
		Element nameNodeInformation = networkElement.getChild(Broker.NAMENODE_S);
		String nameNodeIp = nameNodeInformation.getAttributeValue(Broker.IP);
		int nameNodePort = Integer.parseInt(nameNodeInformation.getAttributeValue(Broker.PORT));
		String nameNodeCID = nameNodeInformation.getAttributeValue(Broker.CID_S);
		
		NodeInformation nodeInformation = new NodeInformation(nameNodeIp, nameNodeCID, nameNodePort);
		Registry.setNamenodeInformation(nodeInformation);
		
		System.out.println("name node info : [" + nameNodeIp + "," + nameNodePort + "]");
	}

	public static HostInfo getNameNodeHostInfo() {
		NodeInformation nameNodeInfo = Registry.getNamenodeInformation();
		HostInfo nameHostInfo = new HostInfo(nameNodeInfo.getIp(), nameNodeInfo.getPort());
		nameHostInfo.setCid(nameNodeInfo.getCid());
		return nameHostInfo;
	}

	public static void printResult(BrokerResult result) {
		DataResultPrinter.confirm(result);
	}

	
	public static Class<?> getMappingType(Class<?> klass) {
		
		String klassName = klass.getSimpleName();
		
		Class<?>mappedClass = buildClassType(klassName);
		
		if(mappedClass != null) {
		
			return mappedClass;
		}

		return klass;
	}

	private static Class<?> buildClassType(String klassName) {

		if(klassName.equals(DataStore.INTEGER)) {
			return int.class;
		} else if(klassName.equals(DataStore.FLOAT)) {
			return float.class;
		} else if(klassName.equals(DataStore.DOUBLE)) {
			return double.class;
		} else if(klassName.equals(DataStore.LONG)) {
			return long.class;
		} else if(klassName.equals(DataStore.CHARACTER)) {
			return char.class;
		} else if(klassName.equals(DataStore.BOOLEAN)) {
			return boolean.class;
		} else if(klassName.equals(DataStore.BYTE)) {
			return byte.class;
		} 
		
		return null;
	}

	public static String getMethodName(String typeClassName) {

		System.out.println("typeClassName: " + typeClassName);
		
		String methodName = DataStore.SETTER;
		
		Class<?> klass = null;
		try {
			klass = Class.forName(typeClassName);
			
			if(klass.equals(Integer.class)) {
				String intTypeName = Integer.TYPE.getName();
				methodName = methodName + intTypeName.substring(0, 1).toUpperCase() + intTypeName.substring(1, intTypeName.length()) ;
				
			} else {
				String simpleClassName = klass.getSimpleName();
				methodName = methodName + simpleClassName;
			}

			System.out.println("methodName: " + methodName);
			return methodName;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return methodName;
		
	}

	public static Method getMethod(PreparedStatement preparedStatement, String typeClassName) {

		String methodName = getMethodName(typeClassName);
		
		try {
			Class<?> klass = Class.forName(typeClassName);
			
			System.out.println("class name: " + klass.getName());

			Class<?>mappedType = getMappingType(klass);
			
			Class<?>[] parameterTypes = new Class[]{Integer.TYPE, mappedType};
			
			return preparedStatement.getClass().getMethod(methodName, parameterTypes);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} 
		
		return null;
	}

}
